/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package me.panpf.sketch;

import me.panpf.sketch.drawable.MiPixmapElement;
import me.panpf.sketch.util.Log;
import me.panpf.sketch.zoom.PixmapBuild;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.app.Context;
import ohos.global.resource.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.utils.net.Uri;
import pl.droidsonroids.gif.GifDecoder;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Gif
 */
public class Gif extends SketchImageView {

    private static HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x000110, "GifImage");
    Context mContext;
    private List<PixelMap> pixelMapList = new ArrayList<>();

    // 动画侦听函数
    private final AnimatorValue.ValueUpdateListener mAnimatorUpdateListener = (animatorValue, v1) -> {
        int size = pixelMapList.size();
        if (size == 0) {
            return;
        }
        int position;
        if (((int) v1 * size) == size) {
            position = size - 1;
        } else {
            position = (int) (v1 * size);
        }

        PixmapBuild build = new PixmapBuild(null);
        build.setPixelMap(pixelMapList.get(position));
        setImageDrawable(new MiPixmapElement(build));
    };

    // 动画
    private AnimatorValue animatorValue;
    private ImageSource imageSource;
    private GifDecoder gifDecoder;
    private Boolean ispaused = false;
    private int duration;
    private float speed = 1;
    private int i1;

    public Gif(Context context) {
        super(context);
        mContext = context;
        gifDecoder = new GifDecoder();
    }

    public Gif(Context context, AttrSet attrSet) throws IOException, NotExistException, WrongTypeException {
        super(context, attrSet);
        mContext = context;
        gifDecoder = new GifDecoder();
        ResourceManager resourceManager = context.getResourceManager();
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        sourceOptions.formatHint = "image/gif";

        if (attrSet.getAttr("image_src").isPresent()) {
            String id = attrSet.getAttr("image_src").get().getStringValue();
            Pattern pattern = Pattern.compile("[^0-9]");
            Matcher matcher = pattern.matcher(id);
            String all = matcher.replaceAll("");
            RawFileEntry rawFileEntry = resourceManager.getRawFileEntry(resourceManager.getMediaPath(Integer.parseInt(all)));
            ImageSource imageSourceTemp = ImageSource.create(rawFileEntry.openRawFile(), sourceOptions);
            gifDecoder.read(rawFileEntry.openRawFile(), (int) rawFileEntry.openRawFileDescriptor().getFileSize());

            if (imageSourceTemp != null) {
                init(imageSourceTemp);
            }
        } else {
            invalidate();
        }
    }

    public Gif(Context context, int resId) throws NotExistException, WrongTypeException, IOException {
        super(context);
        mContext = context;
        ResourceManager manager = context.getResourceManager();
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        sourceOptions.formatHint = "image/gif";
        RawFileEntry rawFileEntry = manager.getRawFileEntry(manager.getMediaPath(resId));
        ImageSource imageSourceTemp = ImageSource.create(rawFileEntry.openRawFile(), sourceOptions);
        gifDecoder.read(rawFileEntry.openRawFile(), (int) rawFileEntry.openRawFileDescriptor().getFileSize());

        if (imageSourceTemp != null) {
            init(imageSourceTemp);
        }
    }

    public Gif(Context context, ImageSource imageSource) {
        this(context);
        load(imageSource);
    }

    public Gif(Context context, InputStream inputStream) {
        this(context);
        load(inputStream);
    }

    public Gif(Context context, File file) {
        this(context);
        load(file);
    }

    public Gif(Context context, Uri contentUri) {
        this(context);
        load(contentUri);
    }

    public Gif(Context context, byte[] data) {
        this(context);
        load(data);
    }

    public Gif(Context context, String path) {
        this(context);
        try {
            load(path);
        } catch (IOException ignored) {
            Log.error("sketch", ignored.getMessage());
        }
    }

    /**
     * 设置速度
     *
     * @param speed1 速度
     * @return Gif
     */
    public Gif setSpeed(float speed1) {
        float epsinon = (float) 0.00001;
        if (speed1 > epsinon) {
            this.speed = speed1;
        }
        HiLog.info(label, "speed_value" + (speed));
        animatorValue.stop();
        animatorValue.setDuration((long) (speed * duration));
        animatorValue.start();
        invalidate();
        return this;
    }

    private void init(ImageSource imageSource) {
        pixelMapList.clear();
        duration = 0;
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        decodingOptions.allowPartialImage = true;
        i1 = 0;
        if (gifDecoder.getFrameCount() > 0) {
            while (i1 < gifDecoder.getFrameCount()) {
                pixelMapList.add(imageSource.createPixelmap(i1, decodingOptions));
                duration += gifDecoder.getDelay(i1);
                i1++;
            }
        } else {
            try {
                while (imageSource.createPixelmap(i1, decodingOptions) != null) {
                    pixelMapList.add(imageSource.createPixelmap(i1, decodingOptions));
                    duration += 30d;
                    i1++;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 启动动画
        animatorValue = new AnimatorValue();
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setDelay(100);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setDuration(duration == 0 ? 3000 : duration);
        animatorValue.setValueUpdateListener(mAnimatorUpdateListener);
        animatorValue.start();
    }

    /**
     * 加载 InputStream
     *
     * @param is 输入流
     */
    public void load(InputStream is) {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(is, sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载 data byte
     *
     * @param data byte[]
     */
    public void load(byte[] data) {
        gifDecoder.read(data);
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(data, sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载   data ByteBuffer
     *
     * @param data ByteBuffer
     */
    public void load(ByteBuffer data) {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(data, sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载 Callable<RawFileDescriptor>
     *
     * @param callable Callable<RawFileDescriptor>
     */
    public void load(Callable<RawFileDescriptor> callable) {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(callable, sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载  File
     *
     * @param file 文件
     */
    public void load(File file) {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(file, sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载 FileDescriptor
     *
     * @param fd FileDescriptor
     */
    public void load(FileDescriptor fd) {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(fd, sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载 pathName
     *
     * @param pathName 地址
     * @throws IOException
     */
    public void load(String pathName) throws IOException {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();

        ResourceManager manager = mContext.getResourceManager();
        RawFileEntry rawFileEntry = manager.getRawFileEntry(pathName);
        imageSource = ImageSource.create(rawFileEntry.openRawFile(), sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载 rawFileEntry
     *
     * @param rawFileEntry 资源文件
     * @throws IOException 异常
     */
    public void load(RawFileEntry rawFileEntry) throws IOException {
        gifDecoder.read(rawFileEntry.openRawFile(), (int) rawFileEntry.openRawFileDescriptor().getFileSize());
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(rawFileEntry.openRawFile(), sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * load
     * @param imageSource
     */
    public void load(ImageSource imageSource) {
        this.imageSource = imageSource;
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 加载 Uri
     *
     * @param uri uri地址
     */
    public void load(Uri uri) {
        ImageSource.SourceOptions sourceOption = new ImageSource.SourceOptions();
        imageSource = ImageSource.create(uri.getDecodedPath(), sourceOption);
        if (imageSource != null) {
            init(imageSource);
        }
    }

    /**
     * 暂停
     */
    public void pause() {
        if (!ispaused) {
            ispaused = true;
        }
        animatorValue.pause();
        invalidate();
    }

    /**
     * 开始
     */
    public void play() {
        if (ispaused) {
            ispaused = false;
        }
        animatorValue.start();
    }

    /**
     * 获取持续时间
     *
     * @return 获取持续时间
     */
    public int getDuration() {
        return duration;
    }

    /**
     * 是否开始
     *
     * @return 是否开始
     */
    public Boolean isInPlaying() {
        return !ispaused;
    }

    /**
     * 重置
     */
    public void reset() {
        animatorValue.stop();
        animatorValue.start();
        invalidate();
    }

    /**
     * 是否循环
     *
     * @return 是否循环
     */
    public boolean isRecycled() {
        return imageSource == null;
    }

    /**
     * 回收
     */
    public void recycle() {
        imageSource = null;
    }

    public ImageSource getImageSource() {
        return imageSource;
    }
}